﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Markup;
using System.Xaml;
using System.Xaml.Schema;

using agree.semi;

using alib;
using alib.Array;
using alib.Collections;
using alib.Debugging;
using alib.Dictionary;
using alib.String;
using alib.Enumerable;

namespace agree.mrs
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public interface ISemantics : IIdentity
	{
		Constant RegisterConstant(String value);
		//Variable CreateInstance(SemType t);
		Variable CreateInstance(System.Type sem_type);
		//Variable CreateInstance<T>() where T : type.Variable;
		SemType GetSemType<T>() where T : SemType;
	};

	public interface SemType
	{
		String Name { get; }
	};
	namespace type
	{
		public interface Constant : SemType { };
		public interface Variable : SemType { };
		public interface Index : Variable { };
		public interface H : Variable { };
		public interface E : Index { };
		public interface X : Index { };
		public interface U : Index { };
	}

	public interface ISemValue
	{
		String Name { get; }
	};

	//public interface IConstant : ISemValue
	//{
	//};

	//public interface IVariable : ISemValue
	//{
	//};

	public interface IConstraint : ISemValue, IReadOnlyList<IProperty>
	{
		//SemType Type { get; }
		//ISemValue this[String name] { get; }
		String Type { get; }
		String this[String name] { get; }
	};

	public interface IProperty /* : ISemantics */
	{
		String Name { get; }
		//ISemValue Value { get; }
		ISemValue Value { get; }
	};

#if false
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class Semantics : ISemantics
	{
		public Semantics(ISemantics sem)
		{
			this.sem = sem;
		}
		public readonly ISemantics sem;

		public virtual Constant RegisterConstant(string value)
		{
			throw not.impl;
		}

		public virtual Variable CreateInstance<T>() where T : type.Variable
		{
			throw not.impl;
		}
	};
#endif

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class SemValue : ISemValue
	{
		public SemValue(ISemantics sem)
		{
		}

		public abstract String Name { get; }
	};



	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{_name,nq}")]
	public sealed class Constant : SemValue, type.Constant// IConstant
	{
		public Constant(ISemantics sem, String value)
			: base(sem)
		{
			this._name = value;
		}
		String _name;
		public override String Name { get { return _name; } }
		public override String ToString() { return _name; }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[ContentProperty("Properties")]
	[DebuggerDisplay("{ToString(),nq}")]
	public class Constraint : IConstraint
	{
		public Constraint(ISemantics sem, String type)
		{
			this.sem = sem;
			this._type = type;
			this.a = Collection<Property>.None;
		}
		protected ISemantics sem;

		//readonly SemType _type;
		//public SemType Type { get { return _type; } }

		readonly String _type;
		public String Type { get { return _type; } }

		public virtual String Name { get { return _type; } set { throw not.impl; } }

		public void Add(String name, String value)
		{
			for (int i = 0; i < a.Length; i++)
				if (StringComparer.OrdinalIgnoreCase.Equals(a[i].Name, name))
				{
					a[i].Value = new Constant(sem, value);
					return;
				}
			arr.Append(ref a, new Property(sem, name, value));
		}

		Property[] a;

		public String this[String name]
		{
			get
			{
				var _tmp = a;
				for (int i = 0; i < _tmp.Length; i++)
					if (_tmp[i].Name.Equals(name, StringComparison.OrdinalIgnoreCase))
						return _tmp[i].Value.Name;
				return null;
			}
		}

		public IProperty this[int index]
		{
			get { return a[index]; }
		}

		public int Count { get { return a.Length; } }

		public IEnumerator<IProperty> GetEnumerator() { return a.Enumerator(); }

		IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

		public override String ToString()
		{
			var sb = new StringBuilder();
			sb.Append(this is Variable ? ((Variable)this).Name : _type);

			if (Count > 0)
			{
				sb.Append(" { ");
				sb.Append(this.Select(x => String.Format("{0} {1}", x.Name, x.Value)).StringJoin(", "));
				sb.Append(" }");
			}
			return sb.ToString();
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[ContentProperty("Properties")]
	[DebuggerDisplay("{ToString(),nq}")]
	public class Variable : Constraint, type.Variable, agree.schema.ρρName
	{
		public Variable(ISemantics sem, String type, int num)
			: base(sem, type)
		{
			this.num = num;
		}
		public Mrs mrs { get { return (Mrs)sem; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly int num;

		public override String Name
		{
			get { return Type + num.ToString(); }
			set { throw not.valid; }
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IEnumerable<ElementRole> Usage
		{
			get { return mrs.ElementRoles.Where(er => er.role.var == this); }
		}

		public String FormatFirstUse(BitArray var_disp_bits)
		{
			if (var_disp_bits != null)
			{
				if (var_disp_bits[num])
					return this.Name;
				var_disp_bits[num] = true;
			}
			return base.ToString();
		}

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public ElementRole[] _dbg { get { return Usage.ToArray(); } }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class Handle : Variable, type.H
	{
		public Handle(ISemantics sem, int num)
			: base(sem, "h", num)
		{
		}
	};
	public class Event : Variable, type.E
	{
		public Event(ISemantics sem, int num)
			: base(sem, "e", num)
		{
		}
	};
}